package cn.kivensoft.util;

import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.lang.ref.WeakReference;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.TimeZone;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.ObjIntConsumer;

/**格式化到动态字符串缓冲区的类，采取缓存方式实现，增强对日期、数组、列表的格式化
 * @author Kiven Lee
 * @version 2.0
 */
final public class Fmt implements Appendable, CharSequence {
	@FunctionalInterface
	public interface FmtComsumer {
		void accept(Fmt fmt, int index, FmtType type);
	}

	// 允许放入对象池的对象最大长度
	private static final int REUSE_MAX_LEN = 1024;
	private static final String SEP = ", ";
	private static final String PREFIX = "[";
	private static final String SUFFIX = "]";
	private static final String KV_SEP = ": ";
	private static final String KV_PREFIX = "{";
	private static final String KV_SUFFIX = "}";

	// 全局无锁非阻塞堆栈头部指针, 每次获取对象时尝试从head中获取第一个
	private static WeakReference<Fmt> HEAD = null;
	private static final ThreadLocal<String> NEW_LLINE = ThreadLocal.withInitial(System::lineSeparator);
	private static final ReentrantLock LOCK = new ReentrantLock();
	// 全局json格式化函数
	private static volatile Function<Object, String> FMT_JSON_FUNC = null;

	public enum FmtType { NONE, JSON, BASE64, HEX, DATE, TIME }

	// 指向自身的弱引用对象
	private final WeakReference<Fmt> self;
	// 指向下一个缓存项位置
	private volatile WeakReference<Fmt> next;
	private final StringBuilder buffer;
	private volatile boolean recycled;
	private int lastUtf8Char = 0, requireUtf8Count = 0; // 上次读取结果及缺少的字节数

	// 无锁非阻塞弹出栈顶元素
	private static Fmt pop() {
		Fmt fmt = null;

		// 原子操作获取顶部元素
		if (HEAD != null) {
			LOCK.lock();
			if (HEAD != null) {
				fmt = HEAD.get();
				HEAD = fmt != null ? fmt.next : null;
			}
			LOCK.unlock();
		}

		// 返回对象脱离列表控制
		if (fmt != null) {
			fmt.next = null;
			fmt.recycled = false;
		} else {
			fmt = new Fmt();
		}

		return fmt;
	}

	// 无锁非阻塞元素压入栈顶
	private static void push(Fmt fmt) {
		// 用户重复入栈或者缓冲池容量大于REUSE_MAX_LEN
		if (fmt.recycled || fmt.buffer.capacity() > REUSE_MAX_LEN)
			return;

		fmt.buffer.setLength(0);
		fmt.recycled = true;

		LOCK.lock();
		fmt.next = HEAD;
		HEAD = fmt.self;
		LOCK.unlock();
	}

	// 构造函数私有化, 禁止用户直接创建, 只能通过静态函数get获取实例
	private Fmt() {
		buffer = new StringBuilder(128);
		self = new WeakReference<>(this);
		next = null;
		recycled = false;
	}

	public static void setFmtJsonFunc(Function<Object, String> func) {
		FMT_JSON_FUNC = func;
	}

	/** 获取缓存中的Fmt实例 */
	public static Fmt get() {
		return pop();
	}

	/** 获取低层的缓冲区对象
	 * @return 内部对象textBuilder
	 */
	public StringBuilder getBuffer() {
		return buffer;
	}

	/** 回收对象, 对象被回收后, 严禁再访问对象, 否则将出现不可预计的结果 */
	public void recycle() {
		push(this);
	}

	public boolean getRecycled() {
		return recycled;
	}

	//静态公共函数-------------------------------------------------------------

	/** 以{}为格式化标识符进行快速格式化，类似日志输出
	 * @param arg 格式化参数
	 * @return 格式化后的字符串
	 */
	public static String fmt(Object arg) {
		return get().append(arg).release();
	}

	/** 以{}为格式化标识符进行快速格式化，类似日志输出
	 * @param format 格式化字符串
	 * @param arg1 格式化参数1
	 * @return 格式化后的字符串
	 */
	public static String fmt(String format, Object arg1) {
		return get()._format(format, 1, arg1, null, null).release();
	}

	/** 以{}为格式化标识符进行快速格式化，类似日志输出
	 * @param format 格式化字符串
	 * @param arg1 格式化参数1
	 * @param arg2 格式化参数2
	 * @return 格式化后的字符串
	 */
	public static String fmt(String format, Object arg1, Object arg2) {
		return get()._format(format, 2, arg1, arg2, null).release();
	}

	/** 以{}为格式化标识符进行快速格式化，类似日志输出
	 * @param format 格式化字符串
	 * @param arg1 格式化参数1
	 * @param arg2 格式化参数2
	 * @param arg3 格式化参数3
	 * @return 格式化后的字符串
	 */
	public static String fmt(String format, Object arg1, Object arg2, Object arg3) {
		return get()._format(format, 3, arg1, arg2, arg3).release();
	}

	/** 以{}为格式化标识符进行快速格式化，类似日志输出
	 * @param format 格式化字符串
	 * @param args 格式化参数
	 * @return 格式化后的字符串
	 */
	public static String fmt(String format, Object... args) {
		return get().format(format, args).release();
	}

	/** 以{}为格式化标识符进行快速格式化，类似日志输出
	 * @param format 格式化字符串
	 * @param func 返回格式化参数的lambda表达式
	 * @return 格式化后的字符串
	 */
	public static String fmt(String format, IntFunction<Object> func) {
		return get().format(format, func).release();
	}

	/** 以{}为格式化标识符进行快速格式化，类似日志输出
	 * @param format 格式化字符串
	 * @param func 返回格式化参数的lambda表达式
	 * @return 格式化后的字符串
	 */
	public static String fmt(String format, FmtComsumer func) {
		return get().format(format, func).release();
	}

	/** 以{}为格式化标识符进行快速格式化, null的对象跳过而不是格式化为"null"
	 * @param format 格式化字符串
	 * @param args 格式化参数
	 * @return 格式化后的字符串
	 */
	public static String fmtString(String format, Object... args) {
		for (int i = 0, imax = args.length; i < imax; ++i)
			if (args[i] == null) args[i] = "";
		return fmt(format, args);
	}

	/** 返回json化后的字符串
	 * @param args key/value格式参数，数量为偶数个，奇数位必须为String类型，偶数位为基本类型
	 * @return 格式化后的字符串
	 */
	public static String fmtJson(String format, Object... args) {
		return get().format(format, (f, i, t) -> f.appendJsonMap(args)).release();
	}

	/** 输出到控制台
	 * @param format 格式化字符串
	 * @param args 格式化参数
	 */
	public static void pl(String format, Object... args) {
		System.out.println(get().format(format, args).release());
	}

	/** 返回json化后的字符串，用缓冲区对象进行
	 * @param value 要json化的参数
	 * @return 格式化后的字符串
	 */
	public static String toJson(Object value) {
		return get().appendJson(value).release();
	}

	/** 返回json化后的字符串
	 * @param args key/value格式参数，数量为偶数个，奇数位必须为String类型，偶数位为基本类型
	 * @return 格式化后的字符串
	 */
	public static String toJsonMap(Object... args) {
		return get().appendJsonMap(args).release();
	}

	/** 连接2个字符串成1个 */
	public static String concat(String arg1, String arg2) {
		Fmt f = get();
		f.buffer.append(arg1).append(arg2);
		return f.release();
	}

	/** 连接3个字符串成1个 */
	public static String concat(String arg1, char arg2, String arg3) {
		Fmt f = get();
		f.buffer.append(arg1).append(arg2).append(arg3);
		return f.release();
	}

	/** 连接3个字符串成1个 */
	public static String concat(String arg1, String arg2, String arg3) {
		Fmt f = get();
		f.buffer.append(arg1).append(arg2).append(arg3);
		return f.release();
	}

	/** 连接多个字符串成1个 */
	public static String concat(String... args) {
		Fmt f = get();
		for (String arg : args) f.buffer.append(arg);
		return f.release();
	}

	/** 连接多个字符串成1个 */
	public static String concat(Object... args) {
		Fmt f = get();
		for (Object arg : args) f.append(arg);
		return f.release();
	}

	/** 生成指定重复数量的字符串
	 * @param c 指定重复的字符
	 * @param count 重复数量
	 * @return 字符串结果
	 */
	public static String rep(char c, int count) {
		return Fmt.get().repeat(c, count).release();
	}

	/** 生成指定重复次数的字符串
	 * @param text 指定要重复的字符串
	 * @param count 重复数量
	 * @return 生成的字符串
	 */
	public static String rep(String text, int count) {
		return get().repeat(text, count, null).release();
	}

	/** 返回格式化后的字符串，用缓冲区对象进行
	 * @param array 要格式化的数组
	 * @param sep 分隔符
	 * @return 格式化后的字符串
	 */
	public static <T> String join(T[] array, String sep) {
		return get().append(array, sep, null, null).release();
	}

	/** 返回格式化后的字符串，用缓冲区对象进行
	 * @param array 要格式化的数组
	 * @param sep 分隔符
	 * @param prefix 前缀字符串
	 * @param suffix 后缀字符串
	 * @return 格式化后的字符串
	 */
	public static <T> String join(T[] array, String sep, String prefix, String suffix) {
		return get().append(array, sep, prefix, suffix).release();
	}

	/** 返回格式化后的字符串，通过回调接口进行格式化
	 * @param count 要格式化的元素数量
	 * @param sep 分隔符
	 * @param prefix 前缀字符串
	 * @param suffix 后缀字符串
	 * @param func lamdba表达式,参数是(Fmt, index)
	 * @return 格式化后的字符串
	 */
	public static <T> String join(int count, String sep, String prefix, String suffix,
								  ObjIntConsumer<Fmt> func) {
		Fmt f = get();
		f.appendMore(count, sep, prefix, suffix, func);
		return f.release();
	}

	/** 返回格式化后的字符串
	 * @param iter 要格式化的参数
	 * @param sep 分隔符
	 * @return 格式化后的字符串
	 */
	public static <T> String join(Iterable<T> iter, String sep) {
		return get().append(iter, sep, null, null).release();
	}

	/** 返回格式化后的字符串
	 * @param iter 要格式化的参数
	 * @param sep 分隔符
	 * @param prefix 前缀字符串
	 * @param suffix 后缀字符串
	 * @return 格式化后的字符串
	 */
	public static <T> String join(Iterable<T> iter, String sep, String prefix, String suffix) {
		return get().append(iter, sep, prefix, suffix).release();
	}

	/** 返回格式化后的字符串
	 * @param iter 要格式化的参数
	 * @param sep 分隔符
	 * @param prefix 前缀字符串
	 * @param suffix 后缀字符串
	 * @param func lamdba表达式,参数是(Fmt, T)
	 * @return 格式化后的字符串
	 */
	public static <T> String join(Iterable<T> iter, String sep, String prefix,
								  String suffix, BiConsumer<Fmt, T> func) {
		Fmt f = get();
		f.appendMore(iter, sep, prefix, suffix, func);
		return f.release();
	}

	/** 连接多个字符串合成的路径 */
	public static String concatPaths(String... paths) {
		Fmt f = Fmt.get();
		for (String path : paths) f.appendPath(path);
		return f.release();
	}

	/** 获取平台相关的回车换行符
	 * @return 回车换行符
	 */
	public static String NL() {
		return NEW_LLINE.get();
	}

	/** 返回缓冲区长度 */
	@Override
	public int length() {
		return buffer.length();
	}

	/** 返回缓冲区的utf8编码长度 */
	public int utf8Length() {
		return utf8Length(0, buffer.length());
	}

	/** 返回缓冲区的utf8编码长度 */
	public int utf8Length(int begin, int end) {
		int count = 0;
		for (; begin < end; ++begin) {
			char c = buffer.charAt(begin);
			if (c >= 0xD800 && c <= 0xDFFF) {
				count += 4;
				++begin;
			} else
				count += c < 0x80 ? 1 : c < 0x800 ? 2 : 3;
		}
		return count;
	}

	/** 获取指定位置的字符 */
	@Override
	public char charAt(int index) {
		return buffer.charAt(index);
	}

	/** 设置指定位置的字符 */
	public void setCharAt(int index, char c) {
		buffer.setCharAt(index, c);
	}

	@Override
	public CharSequence subSequence(int begin, int end) {
		return buffer.substring(begin, end);
	}

	@Override
	public Fmt append(CharSequence csq) {
		buffer.append(csq);
		return this;
	}

	@Override
	public Fmt append(CharSequence csq, int begin, int end) {
		buffer.append(csq, begin, end);
		return this;
	}

	@Override
	public Fmt append(char c) {
		buffer.append(c);
		return this;
	}

	public Fmt append(boolean b) {
		buffer.append(b);
		return this;
	}

	public Fmt append(int i) {
		buffer.append(i);
		return this;
	}

	public Fmt append(long l) {
		buffer.append(l);
		return this;
	}

	public Fmt append(float f) {
		buffer.append(f);
		return this;
	}

	public Fmt append(double d) {
		buffer.append(d);
		return this;
	}

	public Fmt append(String s) {
		return s == null ? appendNull() : append(s, 0, s.length());
	}

	public Fmt append(String s, int begin, int end) {
		if (s == null) appendNull();
		else buffer.append(s, begin, end);
		return this;
	}

	public Fmt append(char[] str) {
		return str == null ? appendNull() : append(str, 0, str.length);
	}

	public Fmt append(char[] str, int begin, int end) {
		if (str == null) appendNull();
		else buffer.append(str, begin, end);
		return this;
	}

	public Fmt append(byte[] utf8_bytes) {
		return utf8_bytes == null ? appendNull() : append(utf8_bytes, 0, utf8_bytes.length);
	}

	public Fmt append(byte[] utf8_bytes, int begin, int end) {
		if (utf8_bytes == null) {
			return appendNull();
		} else {
			resetUtf8Flag();
			return appendContinue(utf8_bytes, begin, end);
		}
	}


	/** 分段添加utf8格式内容, 适用于多次读取, 有可能一次读取的内容utf8被割裂的情况 */
	public Fmt appendContinue(byte[] utf8_bytes) {
		return utf8_bytes == null ? appendNull() : appendContinue(utf8_bytes, 0, utf8_bytes.length);
	}

	/** 分段添加utf8格式内容, 适用于多次读取, 有可能一次读取的内容utf8被割裂的情况 */
	public Fmt appendContinue(byte[] utf8_bytes, int begin, int end) {
		if (utf8_bytes == null || utf8_bytes.length == 0 || end <= begin) return this;

		// 上次处理剩余字节信息的本地变量设置
		int b = requireUtf8Count > 0 ? lastUtf8Char : 0, reqc = requireUtf8Count;
		requireUtf8Count = 0;

		while (begin < end) {
			// 如果上次读取的utf8不完整, 则跳过本次读取, 先行处理剩余字符
			if (reqc == 0) {
				b = utf8_bytes[begin++] & 0xFF;

				// ascii字符直接处理, 然后进入下一次循环
				if (b < 0x80) {
					buffer.append((char) b);
					continue;
				}

				// 非ascii字符, 根据第一个字节, 计算出后面还需要几个字节
				if (b < 0xC0) throw new RuntimeException("bad byte to transaction utf8");
				reqc = b < 0xE0 ? 1 : b < 0xF0 ? 2 : b < 0xF8 ? 3 : b < 0xFC ? 4 : 5;
				b &= 0x3F >> reqc; // 将第一个字节解码
			}

			// 解码一个unicode中剩余的utf8字节
			int next_pos = begin + reqc;
			for (int imax = Math.min(next_pos, end); begin < imax; ++begin)
				b = (b << 6) | (utf8_bytes[begin] & 0x3F);
			// reqc只在第一次循环处理剩余字节时才有可能不为0, 后续循环固定为0
			reqc = 0;

			// 本次解码到末尾依然不完整, 记录剩余字节信息
			if (next_pos > end) {
				lastUtf8Char = b;
				requireUtf8Count = next_pos - end;
			}
			// 完整解码一个unicode, 写入缓冲区, 注意: 一个unicode字符有可能是2个char编码
			else {
				if (b <= 0xFFFF) buffer.append((char) b);
				else if (b <= 0xEFFFF) {
					buffer.append((char) (0xD800 + (b >> 10) - 0x40));
					buffer.append((char) (0xDC00 + (b & 0x3FF)));
				}
				else throw new RuntimeException("bad byte to transaction utf8");
			}
		}

		return this;
	}

	/** 重置分段添加utf8格式参数, 强制初始化 */
	public Fmt resetUtf8Flag() {
		lastUtf8Char = 0;
		requireUtf8Count = 0;
		return this;
	}

	/** 设置新的长度 */
	public Fmt setLength(int newLen) {
		buffer.setLength(newLen);
		return this;
	}

	/** 删除指定区间的字符, 后面的前移 */
	public Fmt delete(int begin, int end) {
		buffer.delete(begin, end);
		return this;
	}

	/** 删除末尾指定数量的字符 */
	public Fmt remove(int count) {
		buffer.setLength(buffer.length() - count);
		return this;
	}

	public String substring(int begin) {
		return buffer.substring(begin);
	}

	public String substring(int begin, int end) {
		return buffer.substring(begin, end);
	}

	@Override
	public String toString() {
		return buffer.toString();
	}

	/** 将字符串内容转成UTF-8字节数组返回
	 * @return 返回的字节数组
	 */
	public byte[] toBytes() {
		return Strings.toBytes(buffer, 0, buffer.length());
	}

	/** 将字符串内容转成UTF-8字节数组返回
	 * @param begin 起始位置
	 * @param end 结束位置
	 * @return 返回的字节数组
	 */
	public byte[] toBytes(int begin, int end) {
		return Strings.toBytes(buffer, begin, end);
	}

	/** 将指定区间的字符转码成utf8写入到目标字节数组
	 * @param dst 目标字节数组
	 * @param dstBegin 目标起始位置
	 */
	public void getBytes(byte[] dst, int dstBegin) {
		getBytes(0, buffer.length(), dst, dstBegin);
	}

	/** 将指定区间的字符转码成utf8写入到目标字节数组
	 * @param srcBegin 源起始位置
	 * @param srcEnd 源结束位置
	 * @param dst 目标字节数组
	 * @param dstBegin 目标起始位置
	 */
	public void getBytes(int srcBegin, int srcEnd, byte[] dst, int dstBegin) {
		int[] pos = { dstBegin };
		Strings.utf8Encode(buffer, srcBegin, srcEnd, (chs, len) -> {
			System.arraycopy(chs, 0, dst, pos[0], len);
			pos[0] += len;
			return len;
		});
	}

	/** 将内容转成char[]数组并返回该数组 */
	public void getChars(char[] dst, int dstBegin) {
		buffer.getChars(0, buffer.length(), dst, dstBegin);
	}

	/** 将指定区间的内容转成char[]数组并返回该数组*/
	public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) {
		buffer.getChars(srcBegin, srcEnd, dst, dstBegin);
	}

	/** 回收对象，返回对象生成的字符串 */
	public String release() {
		String ret = buffer.toString();
		recycle();
		return ret;
	}

	/** 回收对象，返回对象生成的字符串 */
	public String release(int begin) {
		String ret = buffer.substring(begin);
		recycle();
		return ret;
	}

	/** 回收对象，返回对象生成的字符串 */
	public String release(int begin, int end) {
		String ret = buffer.substring(begin, end);
		recycle();
		return ret;
	}

	/** 将内容输出到系统控制台输出流并回收对象 */
	public void output() throws IOException {
		output(System.out);
	}

	/** 将内容输出到输出流并回收对象 */
	public void output(OutputStream out) throws IOException {
		IOException[] err = { null };
		Strings.utf8Encode(this, 0, buffer.length(), (bs, len) -> {
			try {
				out.write(bs, 0, len);
				return len;
			} catch (IOException e) {
				err[0] = e;
				return 0;
			}
		});
		if (err[0] != null) throw err[0];
		recycle();
	}

	/** 将内容输出到输出流并回收对象 */
	public void output(Writer w) throws IOException {
		w.append(buffer);
		recycle();
	}

	/** 使用{}作为格式化参数进行格式化 */
	public Fmt format(String format, Object... args) {
		int len = args.length;
		if (len == 0) buffer.append(format);
		else format(format, i -> i < len ? args[i] : null);
		return this;
	}

	/** 使用{}作为格式化参数进行格式化
	 * @param format 字符串格式模板
	 * @param arg1 格式化参数1
	 * @return this
	 */
	public Fmt format(String format, Object arg1) {
		return _format(format, 1, arg1, null, null);
	}

	/** 使用{}作为格式化参数进行格式化
	 * @param format 字符串格式模板
	 * @param arg1 格式化参数1
	 * @param arg2 格式化参数2
	 * @return this
	 */
	public Fmt format(String format, Object arg1, Object arg2) {
		return _format(format, 2, arg1, arg2, null);
	}

	/** 使用{}作为格式化参数进行格式化
	 * @param format 字符串格式模板
	 * @param arg1 格式化参数1
	 * @param arg2 格式化参数2
	 * @param arg3 格式化参数3
	 * @return this
	 */
	public Fmt format(String format, Object arg1, Object arg2, Object arg3) {
		return _format(format, 3, arg1, arg2, arg3);
	}

	/** 使用{}作为格式化参数进行格式化
	 * @param format 字符串格式模板
	 * @param count 格式化参数个数
	 * @param arg1 格式化参数1
	 * @param arg2 格式化参数2
	 * @param arg3 格式化参数3
	 * @return this
	 */
	private Fmt _format(String format, int count, Object arg1, Object arg2, Object arg3) {
		return format(format, i -> {
			if (i < count) {
				if (i == 0) return arg1;
				else if (i == 1) return arg2;
				else if (i == 2) return arg3;
			}
			return null;
		});
	}

	/** 使用{}作为格式化参数进行格式化 */
	public Fmt format(String format, IntFunction<Object> func) {
		return format(format, (f, i, t) -> {
			Object val = func.apply(i);
			if (val == null) {
				appendNull();
				return;
			}

			switch (t) {
				case JSON:
					f.appendJson(val);
					break;
				case DATE:
					if (val instanceof Date)
						f.appendDate((Date) val);
					else
						f.append(val);
					break;
				case TIME:
					if (val instanceof Date)
						f.appendTime((Date) val);
					else
						f.append(val);
					break;
				case HEX:
					Class<?> cls = val.getClass();
					if (cls == Byte.class) {
						f.appendHex((Byte) val);
					} else if (cls == Integer.class) {
						f.appendHex((Integer) val);
					} else if (cls == Long.class) {
						f.appendHex((Long) val);
					} else if (cls == byte[].class) {
						f.appendHex((byte[]) val);
					} else if (cls == Short.class) {
						f.appendHex((Short) val);
					} else {
						f.append(val);
					}
					break;
				case BASE64:
					if (val.getClass() == byte[].class)
						f.appendBase64((byte[]) val);
					else
						f.append(val);
					break;
				default:
					f.append(val);
			}
		});
	}

	/** 使用{}作为格式化参数进行格式化 */
	public Fmt format(String format, FmtComsumer func) {
		char[] fmt_chars = format.toCharArray();
		for (int i = 0, len = fmt_chars.length, idx = 0; i < len; ++i) {
			// 查找左括号出现的位置
			int old_start = i;
			while (i < len && fmt_chars[i] != '{')
				++i;

			// 先把左括号前的字符添加到输出流
			buffer.append(fmt_chars, old_start, i - old_start);
			if (i < len) {
				// 找到的左括号前导字符是反斜杠, 表明是转义字符
				if (i > 0 && fmt_chars[i - 1] == '\\')
					buffer.setLength(buffer.length() - 1);
				// 找到的左括号后续字符是右括号, 是有效的占位符, 返回跳过右括号的索引位置
				else if (i < len - 1 && fmt_chars[i + 1] == '}') {
					func.accept(this, idx++, FmtType.NONE);
					++i;
					continue;
				} else if (i < len - 2 && fmt_chars[i + 2] == '}') {
					i += 2;
					FmtType ft;
					switch (fmt_chars[i - 1]) {
						case '0': case '1': case '2': case '3': case '4':
						case '5': case '6': case '7': case '8': case '9':
							func.accept(this, fmt_chars[i - 1] - 0x30, FmtType.NONE);
							continue;
						case 'B': case 'b': ft = FmtType.BASE64; break;
						case 'D': case 'd': ft = FmtType.DATE; break;
						case 'J': case 'j': ft = FmtType.JSON; break;
						case 'T': case 't': ft = FmtType.TIME; break;
						case 'X': case 'x': ft = FmtType.HEX; break;
						default: ft = FmtType.NONE;
					}
					func.accept(this, idx++, ft);
					continue;
				}
				buffer.append('{');
			}
		}
		return this;
	}

	/** 添加回车换行,与系统平台相关 */
	public Fmt appendNewLine() {
		buffer.append(NEW_LLINE.get());
		return this;
	}

	/** 添加"null"字符串 */
	@SuppressWarnings("UnusedReturnValue")
	public Fmt appendNull() {
		buffer.append("null");
		return this;
	}

	/** 对象内容追加进缓冲区, 函数自动判断大部分系统自带类型进行追加
	 * @param obj 要追加内容的对象实例
	 * @return this
	 */
	public Fmt append(Object obj) {
		if (obj == null) {
			appendNull();
			return this;
		}

		Class<?> cls = obj.getClass();

		// 判断value实际类型进行相应的添加操作, 按常用程度进行排序, 越常用越排前面
		if (cls == String.class) append((String) obj);
		else if (cls == Integer.class) append(((Integer) obj).intValue());
		else if (cls == Long.class) append(((Long) obj).longValue());
		else if (cls == Date.class || cls == java.sql.Date.class) appendDateTime((Date) obj);
		else if (cls == ArrayList.class || obj instanceof Iterable) append((Iterable<?>) obj);
		else if (cls == HashMap.class) append((Map<?, ?>) obj);
		else if (cls == Boolean.class) append(((Boolean) obj).booleanValue());
		else if (cls.isArray()) appendArray(obj, ", ", "[", "]");
		else if (cls == Float.class) append(((Float) obj).floatValue());
		else if (cls == Double.class) append(((Double) obj).doubleValue());
		else if (obj instanceof CharSequence) append((CharSequence) obj);
		else if (cls == LocalDateTime.class) append((LocalDateTime) obj);
		else if (cls == LocalDate.class) append((LocalDate) obj);
		else if (cls == LocalTime.class) append((LocalTime) obj);
		else if (cls == GregorianCalendar.class) append((GregorianCalendar) obj);
		else if (cls == Character.class) append(((Character) obj).charValue());
		else if (cls == Byte.class) append(((Byte) obj).intValue());
		else if (cls == Short.class) append(((Short) obj).intValue());
		else if (obj instanceof Map) append((Map<?, ?>) obj);
		else if (obj instanceof Calendar) append((Calendar) obj);
		else append(obj.toString());

		return this;
	}

	public Fmt append(Fmt f) {
		buffer.append(f.buffer);
		return this;
	}

	public Fmt append(Fmt f, int begin, int end) {
		buffer.append(f.buffer, begin, end);
		return this;
	}

	/** 格式化日期 */
	public Fmt append(Date date) {
		return appendDateTime(date);
	}

	/** 格式化日期 */
	public Fmt appendDate(Date date) {
		Calendar c = Calendar.getInstance();
		c.setTime(date);
		return appendDate(c);
	}

	/** 格式化日期 */
	public Fmt appendTime(Date date) {
		Calendar c = Calendar.getInstance();
		c.setTime(date);
		return appendTime(c);
	}

	/** 格式化日期 */
	@SuppressWarnings("UnusedReturnValue")
	public Fmt appendDateTime(Date date) {
		Calendar c = Calendar.getInstance();
		c.setTime(date);
		return append(c);
	}

	/** 格式化日期 */
	public Fmt appendGmtDateTime(Date date) {
		Calendar c = Calendar.getInstance();
		c.setTime(date);
		c.setTimeZone(TimeZone.getTimeZone("GMT"));
		return append(c);
	}

	/** 格式化日期 */
	public Fmt append(Calendar calendar) {
		appendDate(calendar);
		buffer.append(' ');
		return appendTime(calendar);
	}

	/** 格式化日期 */
	public Fmt appendDate(Calendar calendar) {
		return appendDate(calendar.get(Calendar.YEAR),
				calendar.get(Calendar.MONTH) + 1,
				calendar.get(Calendar.DATE));
	}

	/** 格式化Calendar对象 */
	public Fmt appendTime(Calendar calendar) {
		return appendTime(calendar.get(Calendar.HOUR_OF_DAY),
				calendar.get(Calendar.MINUTE),
				calendar.get(Calendar.SECOND));
	}

	/** 格式化年月日
	 * @param year 年, 0-9999
	 * @param month 月, 1-12
	 * @param day 日, 1-31
	 * @return this
	 */
	public Fmt appendDate(int year, int month, int day) {
		append(year).append('-');
		if (month < 10) append('0');
		append(month).append('-');
		if (day < 10) append('0');
		append(day);
		return this;
	}

	/** 格式化时分秒
	 * @param hour 24小时, 0-23
	 * @param minute 分钟, 0-59
	 * @param second 秒, 0-59
	 * @return this
	 */
	public Fmt appendTime(int hour, int minute, int second) {
		if (hour < 10) append('0');
		append(hour).append(':');
		if (minute < 10) append('0');
		append(minute).append(':');
		if (second < 10) append('0');
		append(second);
		return this;
	}

	/** 格式化LocalDate对象 */
	public Fmt append(LocalDate date) {
		buffer.append(date);
		return this;
	}

	/** 格式化LocalTime对象 */
	public Fmt append(LocalTime time) {
		buffer.append(time);
		return this;
	}

	/** 格式化LocalDatetime对象 */
	public Fmt append(LocalDateTime datetime) {
		buffer.append(datetime);
		return this;
	}

	public Fmt appendArray(Object obj, String sep, String prefix, String suffix) {
		if (obj == null)
			return appendNull();

		if (prefix != null)
			append(prefix);

		boolean first = true;
		for (int i = 0, imax = Array.getLength(obj); i < imax; ++i) {
			if (first) first = false;
			else append(sep);

			append(Array.get(obj, i));
		}

		if (suffix != null)
			append(suffix);

		return this;
	}

	/** 添加int数组 */
	public Fmt append(int[] ints) {
		return append(ints, SEP, PREFIX, SUFFIX);
	}

	/** 添加int数组
	 * @param ints int数组
	 * @param sep 分隔符, 为null时忽略
	 * @param prefix 前缀字符串, 为null时忽略
	 * @param suffix 后缀字符串, 为null时忽略
	 * @return this
	 */
	public Fmt append(int[] ints, String sep, String prefix, String suffix) {
		return appendArray(ints, sep, prefix, suffix);
	}

	/** 添加int数组 */
	public Fmt append(long[] longs) {
		return append(longs, SEP, PREFIX, SUFFIX);
	}

	/** 添加long数组
	 * @param longs int数组
	 * @param sep 分隔符, 为null时忽略
	 * @param prefix 前缀字符串, 为null时忽略
	 * @param suffix 后缀字符串, 为null时忽略
	 * @return this
	 */
	public Fmt append(long[] longs, String sep, String prefix, String suffix) {
		return appendArray(longs, sep, prefix, suffix);
	}

	/** 添加float数组 */
	public Fmt append(float[] floats) {
		return append(floats, SEP, PREFIX, SUFFIX);
	}

	/** 添加float数组
	 * @param floats int数组
	 * @param sep 分隔符, 为null时忽略
	 * @param prefix 前缀字符串, 为null时忽略
	 * @param suffix 后缀字符串, 为null时忽略
	 * @return this
	 */
	public Fmt append(float[] floats, String sep, String prefix, String suffix) {
		return appendArray(floats, sep, prefix, suffix);
	}

	/** 添加int数组 */
	public Fmt append(double[] doubles) {
		return append(doubles, SEP, PREFIX, SUFFIX);
	}

	/** 添加double数组
	 * @param doubles double数组
	 * @param sep 分隔符, 为null时忽略
	 * @param prefix 前缀字符串, 为null时忽略
	 * @param suffix 后缀字符串, 为null时忽略
	 * @return this
	 */
	public Fmt append(double[] doubles, String sep, String prefix, String suffix) {
		return appendArray(doubles, sep, prefix, suffix);
	}


	/** 格式化数组
	 * @param value 数组
	 * @return this
	 */
	public <T> Fmt append(T[] value) {
		return append(value, SEP, PREFIX, SUFFIX);
	}

	/** 格式化数组
	 * @param value 数组
	 * @param sep 分隔符
	 * @param prefix 格式化前缀
	 * @param suffix 格式化后缀
	 * @return this
	 */
	public <T> Fmt append(T[] value, String sep, String prefix, String suffix) {
		if (value == null)
			return appendNull();

		if (prefix != null)
			append(prefix);

		boolean first = true;
		for (T t : value) {
			if (first) first = false;
			else append(sep);
			append(t);
		}

		if (suffix != null)
			append(suffix);

		return this;
	}

	/** 格式化可迭代对象
	 * @param iter 可迭代对象
	 * @return this
	 */
	public <T> Fmt append(Iterable<T> iter) {
		return append(iter, SEP, PREFIX, SUFFIX);
	}

	/** 格式化可迭代对象
	 * @param iter 可迭代对象
	 * @param sep 字符串分隔符
	 * @param prefix 前缀字符串
	 * @param suffix 后缀字符串
	 * @return this
	 */
	public <T> Fmt append(Iterable<T> iter, String sep, String prefix, String suffix) {
		if (iter == null)
			return appendNull();

		if (prefix != null)
			buffer.append(prefix);

		boolean first = true;
		for (T val : iter) {
			if (first) first = false;
			else buffer.append(sep);

			append(val);
		}

		if (suffix != null)
			buffer.append(suffix);

		return this;
	}

	/** 格式化指定数量的元素
	 * @param count 元素数量
	 * @param sep 分隔符
	 * @param prefix 前缀字符串
	 * @param suffix 后缀字符串
	 * @param func 回调函数, 每次回调返回一个元素
	 * @return this
	 */
	public Fmt append(int count, String sep, String prefix, String suffix, ObjIntConsumer<Fmt> func) {
		appendMore(count, sep, prefix, suffix, (f, i) -> func.accept(this, i));
		return this;
	}

	/** 格式化字典
	 * @param map 字典
	 * @return this
	 */
	public <K, V> Fmt append(Map<K, V> map) {
		return append(map, SEP, KV_SEP, KV_PREFIX, KV_SUFFIX);
	}

	/** 格式化字典
	 * @param map 字典
	 * @param itemSep 字典每项之间的分隔符
	 * @param kvSep 字典key与value之间的分隔符
	 * @param prefix 前缀字符串
	 * @param suffix 后缀字符串
	 * @return this
	 */
	public <K, V> Fmt append(Map<K, V> map, String itemSep, String kvSep, String prefix, String suffix) {
		if (map == null)
			return appendNull();

		if (prefix != null)
			buffer.append(prefix);

		boolean first = true;
		for (Map.Entry<K, V> entry : map.entrySet()) {
			if (first) first = false;
			else buffer.append(itemSep);

			append(entry.getKey());
			buffer.append(kvSep);
			append(entry.getValue());
		}

		if (suffix != null)
			buffer.append(suffix);

		return this;
	}

	/** 格式化多个值模板函数
	 * @param count 元素数量
	 * @param sep 分隔符
	 * @param prefix 前缀文本
	 * @param suffix 后缀文本
	 * @param func 回调接口函数
	 */
	private void appendMore(int count, String sep, String prefix, String suffix, ObjIntConsumer<Fmt> func) {
		if (count < 0) {
			appendNull();
		} else {
			if (prefix != null)
				buffer.append(prefix);
			if (sep == null) {
				for (int i = 0; i < count; ++i)
					func.accept(this, i);
			} else {
				boolean first = false;
				for (int i = 0; i < count; ++i) {
					if (!first) first = true;
					else buffer.append(sep);
					func.accept(this, i);
				}
			}
			if (suffix != null)
				buffer.append(suffix);
		}
	}

	/** 格式化可迭代对象模板函数
	 * @param iter 可迭代的对象
	 * @param sep 分隔符
	 * @param prefix 前缀文本
	 * @param suffix 后缀文本
	 * @param func 回调接口函数
	 */
	private <T> void appendMore(Iterable<T> iter, String sep, String prefix,
			String suffix, BiConsumer<Fmt, T> func) {
		if (iter == null) {
			appendNull();
		} else {
			if (prefix != null)
				buffer.append(prefix);

			boolean first = false;
			for (T t : iter) {
				if (!first)
					first = true;
				else if (sep != null)
					buffer.append(sep);
				func.accept(this, t);
			}

			if (suffix != null)
				buffer.append(suffix);
		}
	}

	/** 添加路径, 判断尾部反斜杠分隔符与path开头分隔符
	 * @param path 路径
	 * @return this
	 */
	@SuppressWarnings("UnusedReturnValue")
	public Fmt appendPath(String path) {
		if (path != null && !path.isEmpty()) {
			int len = buffer.length();
			if (len > 0) {
				char c1 = charAt(len - 1);
				char c2 = path.charAt(0);
				boolean b1 = c1 == '/' || c1 == '\\';
				boolean b2 = c2 == '/' || c2 == '\\';
				if (b1 && b2) buffer.setLength(len - 1);
				else if (!b1 && !b2) buffer.append('/');
			}
			buffer.append(path);
		}
		return this;
	}

	private final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
			99999999, 999999999, Integer.MAX_VALUE };

	/** 追加整数，不足前面补0
	 * @param value 要追加的整数
	 * @param width 宽度，不足前面补0
	 * @return this
	 */
	public Fmt appendInt(int value, int width) {
		int size = 0;
		while (value > sizeTable[size]) ++size;
		int count = width - size - 1;
		while (count-- > 0) buffer.append('0');
		buffer.append(value);
		return this;
	}

	/** 添加文本, 当值为null时忽略 */
	public Fmt appendNotNull(String text) {
		return text != null && !text.isEmpty() ? append(text) : this;
	}

	/** 追加字符串，不足前面补空格
	 * @param text 要追加的文本
	 * @param width 宽度，不足前面补空格
	 * @return this
	 */
	public Fmt appendText(String text, int width) {
		return append(text, width, ' ');
	}

	/** 追加字符串，不足前面补空格
	 * @param text 要追加的文本
	 * @param width 宽度，不足前面补前缀字符
	 * @param prefix 前缀字符
	 * @return this
	 */
	public Fmt appendText(String text, int width, char prefix) {
		if (text == null) return this;
		int count = width - text.length();
		while (count-- > 0) buffer.append(prefix);
		buffer.append(text);
		return this;
	}

	/** 生成指定重复次数的字符串
	 * @param text 需要重复的文本
	 * @param count 重复次数
	 * @return this
	 */
	public Fmt repeat(String text, int count) {
		return repeat(text, count, null);
	}

	/** 生成指定重复次数的字符串
	 * @param text 需要重复的文本
	 * @param count 重复次数
	 * @param delimiter 分隔符
	 * @return this
	 */
	public Fmt repeat(String text, int count, String delimiter) {
		if (count-- > 0)
			buffer.append(text);

		if (delimiter != null)
			while (count-- > 0)
				buffer.append(delimiter).append(text);
		else
			while (count-- > 0)
				buffer.append(text);

		return this;
	}

	/** 生成指定重复次数的字符串
	 * @param c 需要重复的字符
	 * @param count 重复次数
	 * @return this
	 */
	public Fmt repeat(char c, int count) {
		while(--count >= 0) buffer.append(c);
		return this;
	}

	/** 以json字符串方式追加字符串, 自动对字符串进行json方式转义 */
	public Fmt appendJsonString(CharSequence value) {
		if(value == null) appendNull();
		else {
			append('"');
			for (int i = 0, len = value.length(); i < len; ++i) {
				char c = value.charAt(i);
				int finded;
				if (c > '\\') finded = -1; // 小于需要判断的字符的最大值
				else {
					switch (c) {
						case '\b': finded = 'b'; break;
						case '\t': finded = 't'; break;
						case '\f': finded = 'f'; break;
						case '\n': finded = 'n'; break;
						case '\r': finded = 'r'; break;
						//case '\'':
						case '"':
							//case '/':
						case '\\': finded = c; break;
						default: finded = -1;
					}
				}
				if (finded == -1) append(c);
				else append('\\').append((char) finded);
			}
			append('"');
		}
		return this;
	}

	/** 写入简单的对象的json格式
	 * @param args key/value参数，参数个数必须为偶数个，奇数位应该是String类型参数
	 * @return this
	 */
	public Fmt appendJsonMap(Object... args) {
		boolean first = true;
		append("{");

		for (int i = 0, n = args.length - 1; i < n; i += 2) {
			Object v = args[i + 1];

			if (v == null)
				continue;

			if (first) first = false;
			else append(",");

			appendJsonString((String) args[i]).append(":").appendJson(v);
		}

		append("}");
		return this;
	}

	/** 将对象以json格式增加
	 * @param value 要格式化的对象
	 * @return this
	 */
	public Fmt appendJson(Object value) {
		if (FMT_JSON_FUNC != null)
			return append(FMT_JSON_FUNC.apply(value));

		if (value == null)
			return appendNull();

		Class<?> cls = value.getClass();

		if (cls == String.class) appendJsonString((String) value);
		else if (cls == Integer.class) append(((Integer) value).intValue());
		else if (cls == Long.class) append(((Long) value).longValue());
		else if (cls == Date.class || cls == java.sql.Date.class)
			append('"').appendDateTime((Date) value).append('"');
		else if (cls == ArrayList.class || value instanceof Iterable) iterableToJson((Iterable<?>) value);
		else if (cls == HashMap.class) mapToJson((Map<?, ?>)value);
		else if (cls == Boolean.class) append(((Boolean) value).booleanValue());
		else if (cls.isArray()) arrayToJson(value);
		else if (cls == Float.class) append(((Float) value).floatValue());
		else if (cls == Double.class) append(((Double) value).doubleValue());
		else if (cls == Fmt.class) appendJsonString(((Fmt) value).getBuffer());
		else if (cls == LocalDateTime.class)
			append('"').append((LocalDateTime)value).append('"');
		else if (cls == LocalDate.class)
			append('"').append((LocalDate)value).append('"');
		else if (cls == LocalTime.class)
			append('"').append((LocalTime)value).append('"');
		else if (cls == GregorianCalendar.class)
			append('"').append((Calendar)value).append('"');
		else if (cls == BigInteger.class || cls == BigDecimal.class)
			append('"').append(value.toString()).append('"');
		else if (cls == Character.class) charToJson((Character) value);
		else if (cls == Byte.class) append(((Byte) value).intValue());
		else if (cls == Short.class) append(((Short) value).intValue());
		else if (value instanceof CharSequence) appendJsonString((CharSequence) value);
		else if (value instanceof Number) append(value.toString());
		else if (value instanceof Map) mapToJson((Map<?, ?>) value);
		else if (cls.isEnum()) appendJsonString(value.toString());
		else if (value instanceof Calendar)
			append('"').append((Calendar)value).append('"');
		else objectToJson(value);

		return this;
	}

	/** 转换成16进制 */
	public Fmt appendHex(byte[] bytes) {
		return appendHex(bytes, null);
	}

	/** 转换成16进制 */
	public Fmt appendHex(byte[] bytes, String delimiter) {
		Strings.hexEncode(bytes, delimiter, null, (chs, len) -> {
			buffer.append(chs, 0, len);
			return len;
		});
		return this;
	}

	/** 转换成16进制 */
	public Fmt appendHex(byte value) {
		buffer.append(Strings.HEX.charAt((value >>> 4) & 0xF));
		buffer.append(Strings.HEX.charAt(value & 0xF));
		return this;
	}

	/** 转换成16进制 */
	public Fmt appendHex(short value) {
		buffer.append(Strings.HEX.charAt(value >>> 12 & 0xf));
		buffer.append(Strings.HEX.charAt(value >>>  8 & 0xf));
		buffer.append(Strings.HEX.charAt(value >>>  4 & 0xf));
		buffer.append(Strings.HEX.charAt(value & 0xf));
		return this;
	}

	/** 转换成16进制 */
	public Fmt appendHex(int value) {
		buffer.append(Strings.HEX.charAt(value >>> 28));
		buffer.append(Strings.HEX.charAt(value >>> 24 & 0xf));
		buffer.append(Strings.HEX.charAt(value >>> 20 & 0xf));
		buffer.append(Strings.HEX.charAt(value >>> 16 & 0xf));
		buffer.append(Strings.HEX.charAt(value >>> 12 & 0xf));
		buffer.append(Strings.HEX.charAt(value >>>  8 & 0xf));
		buffer.append(Strings.HEX.charAt(value >>>  4 & 0xf));
		buffer.append(Strings.HEX.charAt(value & 0xf));
		return this;
	}

	/** 转换成16进制 */
	public Fmt appendHex(long value) {
		for (int i = 64 - 4; i >= 0; i -= 4)
			buffer.append(Strings.HEX.charAt((int)(value >> i) & 0xf));
		return this;
	}

	/** base64编码
	 * @param bytes 要编码的字节数组
	 * @return 编码后的字符串
	 */
	public Fmt appendBase64(final byte[] bytes) {
		return appendBase64(bytes, true, false);
	}

	/** base64编码
	 * @param bytes 要编码的字节数组
	 * @param lineBreak 是否每76个字符换行标志
	 * @param padding 是否在末尾用=号进行补齐
	 * @return 编码后的字符串
	 */
	public Fmt appendBase64(final byte[] bytes, boolean padding, boolean lineBreak) {
		return _appendBase64(Strings.Base64Type.Standard, bytes, padding, lineBreak);
	}

	/** 转成base64URL格式编码 */
	public Fmt appendBase64Url(byte[] bytes) {
		return appendBase64Url(bytes, true);
	}

	/** base64URL编码
	 * @param bytes 要编码的字节数组
	 * @param padding 是否在末尾用=号进行补齐
	 * @return 编码后的字符串
	 */
	public Fmt appendBase64Url(byte[] bytes, boolean padding) {
		return _appendBase64(Strings.Base64Type.Url, bytes, padding, false);
	}

	private Fmt _appendBase64(Strings.Base64Type type, byte[] bytes, boolean padding, boolean lineBreak) {
		IntNumber pos = new IntNumber();
		Strings.base64Encode(type, padding, lineBreak, (buf, off) -> {
			int len1 = buf.length - off, len2 = bytes.length - pos.value;
			int len = len1 <= len2 ? len1 : len2;
			if (len > 0)
				System.arraycopy(bytes, pos.value, buf, off, len);
			pos.value += len;
			return len;
		}, (chs, len) -> {
			buffer.append(chs, 0, len);
			return len;
		});
		return this;
	}

	private boolean callToJson(Object obj, Method[] ms) {
		for (int i = -1, n = ms.length; ++i < n;)
			if ("toJson".equals(ms[i].getName())) {
				Method m = ms[i];
				Class<?>[] pts = m.getParameterTypes();
				if (m.getReturnType() == Void.class && pts.length == 1 && pts[0] == Fmt.class)
					try {
						m.invoke(obj, this);
						return true;
					} catch (Exception ignored) {}
			}
		return false;
	}

	private void objectToJson(Object obj) {
		Class<?> cls = obj.getClass();
		Method[] ms = cls.getMethods();
		AccessibleObject.setAccessible(ms, true);

		if (callToJson(obj, ms)) return;

		append('{');

		HashSet<String> writedFields = new HashSet<>(); // 存放已经读写的字段
		boolean first = false; // 输出第一个属性时设置为true

		Field[] fs = cls.getFields();
		AccessibleObject.setAccessible(fs, true);

		// 调用公共函数getXXX进行属性输出
		for (int i = 0, n = ms.length; i < n; ++i) {
			try {
				for (; i < n; ++i) {
					Method m = ms[i];
					String mn = m.getName();
					if (mn.length() < 4 || !mn.startsWith("get") || mn.equals("getClass") || m.getParameterCount() > 0)
						continue;

					Object val = m.invoke(obj);
					//属性为空则忽略该属性
					if (val == null)
						continue;

					if (!first) first = true;
					else append(',');

					String field_name = methodToField(mn);
					// 缓存已经写过的字段名称
					writedFields.add(field_name);
					append('"').append(field_name).append("\":");
					appendJson(val);
				}
			} catch (Exception ignored) { }
		}

		// 处理公共属性的字段
		for (int i = 0, n = fs.length; i < n; ++i) {
			try {
				for (; i < n; ++i) {
					Field f = fs[i];
					// 忽略静态成员变量
					if (Modifier.isStatic(f.getModifiers()))
						continue;

					String fn = f.getName();
					// 同名字段已经被getXXX写过, 则忽略公共字段的存取
					if (writedFields.contains(fn))
						continue;

					Object val = f.get(obj);
					if (val == null)
						continue;

					if (!first) first = true;
					else append(',');

					append('"').append(fn).append("\":");
					appendJson(val);
				}
			} catch (Exception ignored) { }
		}

		append('}');
	}

	private void iterableToJson(Iterable<?> iter) {
		append('[');
		Iterator<?> it = iter.iterator();
		if (it.hasNext())
			appendJson(it.next());
		while (it.hasNext()) {
			append(',');
			appendJson(it.next());
		}
		append(']');
	}

	private void charToJson(char value) {
		append('"');

		switch (value) {
			case '\b': append('\\').append('b'); break;
			case '\f': append('\\').append('f'); break;
			case '\n': append('\\').append('n'); break;
			case '\r': append('\\').append('r'); break;
			case '\t': append('\\').append('t'); break;
			case '"': /*case '\'':*/ case '\\': /*case '/':*/
				append('\\').append(value);
				break;
			default: append(value);
		}

		append('"');
	}

	private void mapToJson(Map<?, ?> map) {
		append('{');

		boolean first = false;
		for (Map.Entry<?, ?> entry : map.entrySet()) {
			if (entry.getValue() == null)
				continue;

			if (!first) first = true;
			else append(',');

			appendJsonString(entry.getKey().toString()).append(':')
					.appendJson(entry.getValue());
		}

		append('}');
	}

	private void arrayToJson(Object array) {
		append('[');

		boolean first = false;

		for (int i = 0, imax = Array.getLength(array); i < imax; ++i) {
			if (!first) first = true;
			else append(',');

			appendJson(Array.get(array, i));
		}

		append(']');
	}

	private String methodToField(String methodName) {
		int len = methodName.length();
		char[] tmp = new char[len - 3];
		char c = methodName.charAt(3);
		boolean firstUpper = c >= 'A' && c <= 'Z';
		// 首字符是大写字符且长度为1或者第二个字符不是大写, 则转换首字符为小写, 其它则不变
		if (firstUpper) {
			if (len == 4) c = (char) (c + 0x20);
			else {
				char c2 = methodName.charAt(4);
				if (c2 < 'A' || c2 > 'Z') c = (char) (c + 0x20);
			}
		}
		tmp[0] = c;
		methodName.getChars(4, len, tmp, 1);
		return new String(tmp);
	}
}
